/*
 * Copyright (C) 2011 Chris Gao <chris@exina.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bluewave.goaltracker.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MonthDisplayHelper;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.widget.ImageView;
import com.bluewave.goaltracker.R;

public class CalendarView extends ImageView {
	private static int CELL_WIDTH = 0;
	private static int CELL_HEIGH = 0;
	private static int CELL_MARGIN_TOP = 0;
	private static int CELL_MARGIN_LEFT = 0;
	private static float CELL_TEXT_SIZE;

	private Calendar mRightNow = null;
	private Cell mToday = null;
	private Cell[][] mCells = new Cell[6][7];
	private OnCellTouchListener mOnCellTouchListener = null;
	
	private int trackPeriod,trackDay;

	MonthDisplayHelper mHelper;
	Drawable mDecoration = null;

	public interface OnCellTouchListener {
		public void onTouchCell(MotionEvent event, Cell cell);
		public void onTouchWeek(MotionEvent event);
	}

	public CalendarView(Context context) {
		this(context, null);
	}

	public CalendarView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public CalendarView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mDecoration = context.getResources().getDrawable(
				R.drawable.ic_status_bar);
		
		initCalendarView();
	}

	private void initCalendarView() {
		mRightNow = Calendar.getInstance();
		// prepare static vars
		Resources res = getResources();
	
		CELL_WIDTH = getDipValue(38, res);
		CELL_HEIGH = getDipValue(25, res);
		CELL_MARGIN_TOP = getDipValue(36, res);
		CELL_MARGIN_LEFT = getDipValue(0, res);
		CELL_TEXT_SIZE = getDipValue(18 , res);		
		// set background
		setImageResource(R.drawable.background);
	

		mHelper = new MonthDisplayHelper(mRightNow.get(Calendar.YEAR),
				mRightNow.get(Calendar.MONTH));
		initCells();
	}

	public void setTrackValues(int trackPeriod, int trackDay){
		this.trackPeriod=trackPeriod;
		this.trackDay=trackDay;
	}
	
	public void loadCalendar(Date date) {

		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		mRightNow = cal;
		// prepare static vars
		Resources res = getResources();
	
		CELL_WIDTH = getDipValue(38, res);
		CELL_HEIGH = getDipValue(25, res);
		
		CELL_MARGIN_TOP = getDipValue(36, res);
		CELL_MARGIN_LEFT = getDipValue(0, res);
		CELL_TEXT_SIZE = getDipValue(18, res);		
		
		// set background
		setImageResource(R.drawable.background);
	

		mHelper = new MonthDisplayHelper(mRightNow.get(Calendar.YEAR),
				mRightNow.get(Calendar.MONTH));
		initCells();
	}
	
	public void initCells() {
		class _calendar {
			public int day;
			public boolean thisMonth;

			public _calendar(int d, boolean b) {
				day = d;
				thisMonth = b;
			}

			public _calendar(int d) {
				this(d, false);
			}
		}
		;
		_calendar tmp[][] = new _calendar[6][7];
		int day_month=1;

		for (int i = 0; i < tmp.length; i++) {
			int n[] = mHelper.getDigitsForRow(i);
			for (int d = 0; d < n.length; d++) {
				if (mHelper.isWithinCurrentMonth(i, d))
					tmp[i][d] = new _calendar(n[d], true);
				else
					tmp[i][d] = new _calendar(n[d]);

			}
		}

		// build cells
		Rect Bound = new Rect(CELL_MARGIN_LEFT, CELL_MARGIN_TOP, CELL_WIDTH
				+ CELL_MARGIN_LEFT, CELL_HEIGH + CELL_MARGIN_TOP);
		for (int week = 0; week < mCells.length; week++) {
			for (int day = 0; day < mCells[week].length; day++) {
				if (tmp[week][day].thisMonth) {
					if(trackPeriod==Goal.TrackPeriod.DAILY){
						if (day == 0 || day == 6) {
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new RedCell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}

						}
						else {
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}
						}
					}
					else if(trackPeriod==Goal.TrackPeriod.WEEKDAYS){
						//if(day-1==trackDay){
						if(day!=0 && day!=6){
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}
						}
						else{
							mCells[week][day] = new GrayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						}
					}
					else if(trackPeriod==Goal.TrackPeriod.WEEKENDS){
						//if((trackDay==0&&day==6)||(trackDay==1&&day==0)){
						if(day==0 || day==6){
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}							
						}
						else{
							mCells[week][day] = new GrayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						}
					}
					else if(trackPeriod==Goal.TrackPeriod.WEEKLY){
						if(day==trackDay){
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}							
						}
						else{
							mCells[week][day] = new GrayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						}
					}
					else if(trackPeriod==Goal.TrackPeriod.MONTHLY){
						Calendar cal=Calendar.getInstance();
						if(day_month-1==trackDay || (trackDay>=cal.getActualMaximum(Calendar.DAY_OF_MONTH)&&day_month==cal.getActualMaximum(Calendar.DAY_OF_MONTH))){
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}
						}
						else
							mCells[week][day] = new GrayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
					}
					day_month++;
				} else
					mCells[week][day] = new GrayCell(tmp[week][day].day,
							new Rect(Bound), CELL_TEXT_SIZE);

				Bound.offset(CELL_WIDTH, 0); // move to next column
			}
			Bound.offset(0, CELL_HEIGH); // move to next row and first column
			Bound.left = CELL_MARGIN_LEFT;
			Bound.right = CELL_MARGIN_LEFT + CELL_WIDTH;
		}
	}

	public void markDate(ArrayList<Date> dateList) {
		class _calendar {
			public int day;
			public boolean thisMonth;

			public _calendar(int d, boolean b) {
				day = d;
				thisMonth = b;
			}

			public _calendar(int d) {
				this(d, false);
			}
		}
		;
		_calendar tmp[][] = new _calendar[6][7];
		int day_month=1;

		for (int i = 0; i < tmp.length; i++) {
			int n[] = mHelper.getDigitsForRow(i);
			for (int d = 0; d < n.length; d++) {
				if (mHelper.isWithinCurrentMonth(i, d))
					tmp[i][d] = new _calendar(n[d], true);
				else
					tmp[i][d] = new _calendar(n[d]);

			}
		}

		ArrayList<Date> dates = dateList;
		ArrayList<Integer> days = new ArrayList<Integer>();

		int thisDay = 0;
		mToday = null;

		Calendar markDay = Calendar.getInstance();

		for (int i = 0; i < dates.size(); i++) {

			markDay.setTime(dates.get(i));

			if (mHelper.getYear() == markDay.get(Calendar.YEAR)
					&& mHelper.getMonth() == markDay.get(Calendar.MONTH)) {
				thisDay = markDay.get(Calendar.DAY_OF_MONTH);
				days.add(thisDay);
			}
		}

		// build cells
		Rect Bound = new Rect(CELL_MARGIN_LEFT, CELL_MARGIN_TOP, CELL_WIDTH
				+ CELL_MARGIN_LEFT, CELL_HEIGH + CELL_MARGIN_TOP);
		for (int week = 0; week < mCells.length; week++) {
			for (int day = 0; day < mCells[week].length; day++) {
				if (tmp[week][day].thisMonth) {
					if(trackPeriod==Goal.TrackPeriod.DAILY){
						if (day == 0 || day == 6)
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new RedCell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}
						else if (tmp[week][day].day == new Date().getDate()) {
							mCells[week][day] = new TodayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						} else {
							mCells[week][day] = new Cell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						}
					}
					else if(trackPeriod==Goal.TrackPeriod.WEEKDAYS){
						if(day!=0 && day!=6){
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}
						}
						else{
							mCells[week][day] = new GrayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						}
					}
					else if(trackPeriod==Goal.TrackPeriod.WEEKENDS){
						if(day==0 || day==6){
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}
						}
						else{
							mCells[week][day] = new GrayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						}
					}
					else if(trackPeriod==Goal.TrackPeriod.WEEKLY){
						if(day==trackDay){
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}							
						}
						else{
							mCells[week][day] = new GrayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						}
					}
					else if(trackPeriod==Goal.TrackPeriod.MONTHLY){
						Calendar cal=Calendar.getInstance();
						if(day_month-1==trackDay || (trackDay>=cal.getActualMaximum(Calendar.DAY_OF_MONTH)&&day_month==cal.getActualMaximum(Calendar.DAY_OF_MONTH))){
							if (tmp[week][day].day == new Date().getDate()) {
								mCells[week][day] = new TodayCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE);
							} else {
								mCells[week][day] = new Cell(tmp[week][day].day,
										new Rect(Bound), CELL_TEXT_SIZE);
							}
						}
						else{
							mCells[week][day] = new GrayCell(tmp[week][day].day,
									new Rect(Bound), CELL_TEXT_SIZE);
						}
					}
					day_month++;
				} else
					mCells[week][day] = new GrayCell(tmp[week][day].day,
							new Rect(Bound), CELL_TEXT_SIZE);

				Bound.offset(CELL_WIDTH, 0); // move to next column

				Integer initialDays[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
						12, 13, 14 };

				Integer[] exWeeks = { 0, 4, 5 };

				int curDay = new Date().getDate();

				List<Integer> exWeeksList = Arrays.asList(exWeeks);
				List<Integer> initialDaysList = Arrays.asList(initialDays);

				for (int i = 0; i < days.size(); i++) {
					if (tmp[week][day].day == days.get(i)) {

						if (exWeeksList.contains(week)) {

							if (week == 0) {
								if (initialDaysList.contains(days.get(i))) {

									if (days.get(i) == curDay) {
										Bound.offset(-CELL_WIDTH, 0); // move to
										// next
										// column

										mCells[week][day] = new TodayBlueCell(
												tmp[week][day].day, new Rect(
														Bound), CELL_TEXT_SIZE,
												true, Cell.BLUE_CELL);

										Bound.offset(CELL_WIDTH, 0); // move to
										// next
										// column
									} else {

										Bound.offset(-CELL_WIDTH, 0); // move to
										// next
										// column

										mCells[week][day] = new BlueCell(
												tmp[week][day].day, new Rect(
														Bound), CELL_TEXT_SIZE,
												true, Cell.BLUE_CELL);

										Bound.offset(CELL_WIDTH, 0); // move to
										// next
										// column
									}

								}

							} else {

								Log.i("TODAY", curDay + " - curDay");
								Log.i("TODAY", days.get(i) + " - days.get()");

								if (!initialDaysList.contains(days.get(i))) {
									if (days.get(i) == curDay) {
										Bound.offset(-CELL_WIDTH, 0); // move to
										// next
										// column

										mCells[week][day] = new TodayBlueCell(
												tmp[week][day].day, new Rect(
														Bound), CELL_TEXT_SIZE,
												true, Cell.BLUE_CELL);

										Bound.offset(CELL_WIDTH, 0); // move to
										// next
										// column
									} else {
										Bound.offset(-CELL_WIDTH, 0); // move to
										// next
										// column

										mCells[week][day] = new BlueCell(
												tmp[week][day].day, new Rect(
														Bound), CELL_TEXT_SIZE,
												true, Cell.BLUE_CELL);

										Bound.offset(CELL_WIDTH, 0); // move to
										// next
										// column
									}

								}

							}

						} else {
							if (days.get(i) == curDay) {
								Bound.offset(-CELL_WIDTH, 0); // move to
								// next
								// column

								mCells[week][day] = new TodayBlueCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE, true, Cell.BLUE_CELL);

								Bound.offset(CELL_WIDTH, 0); // move to
								// next
								// column
							} else {
								Bound.offset(-CELL_WIDTH, 0); // move to
								// next
								// column

								mCells[week][day] = new BlueCell(
										tmp[week][day].day, new Rect(Bound),
										CELL_TEXT_SIZE, true, Cell.BLUE_CELL);

								Bound.offset(CELL_WIDTH, 0); // move to
								// next
								// column
							}
						}

					}
				}

			}
			Bound.offset(0, CELL_HEIGH); // move to next row and first column
			Bound.left = CELL_MARGIN_LEFT;
			Bound.right = CELL_MARGIN_LEFT + CELL_WIDTH;

		}
	}

	public void setTimeInMillis(long milliseconds) {
		mRightNow.setTimeInMillis(milliseconds);
		initCells();
		this.invalidate();
	}

	public int getYear() {
		return mHelper.getYear();
	}

	public int getMonth() {
		return mHelper.getMonth();
	}

	public void nextMonth() {
		mHelper.nextMonth();
		initCells();
		invalidate();
	}

	public void previousMonth() {
		mHelper.previousMonth();
		initCells();
		invalidate();
	}

	public boolean firstDay(int day) {
		return day == 1;
	}

	public boolean lastDay(int day) {
		return mHelper.getNumberOfDaysInMonth() == day;
	}

	public void goToday() {
		Calendar cal = Calendar.getInstance();
		mHelper = new MonthDisplayHelper(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH));
		initCells();
		invalidate();
	}

	public Calendar getDate() {
		return mRightNow;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Cell dayForEvent = null;
		if (mOnCellTouchListener != null) {
			for (Cell[] week : mCells) {
				for (Cell day : week) {
					if (day.hitTest((int) event.getX(), (int) event.getY())) {
						dayForEvent = day;
						break;
					}
				}
			}
		}
		
		if (event.getAction() == MotionEvent.ACTION_DOWN && dayForEvent != null) {
			mOnCellTouchListener.onTouchCell(event, dayForEvent);
		}

		mOnCellTouchListener.onTouchWeek(event);
		return true;

	}

	public void setOnCellTouchListener(OnCellTouchListener p) {
		mOnCellTouchListener = p;
	}

	protected void onDraw(Canvas canvas) {
		// draw background
		super.onDraw(canvas);
//		mWeekTitle.draw(canvas);

		// draw cells
		for (Cell[] week : mCells) {
			for (Cell day : week) {
				day.draw(canvas);
			}
		}

		// draw today
		if (mDecoration != null && mToday != null) {
			mDecoration.draw(canvas);
		}
	}

	private class GrayCell extends Cell {
		public GrayCell(int dayOfMon, Rect rect, float s) {
			super(dayOfMon, rect, s);
			type = Cell.GREY_CELL;
			mPaint.setColor(Color.parseColor("#20336699"));

		}
	}

	private class RedCell extends Cell {
		public RedCell(int dayOfMon, Rect rect, float s) {
			super(dayOfMon, rect, s);
		}

	}

	private class BlueCell extends Cell {
		public BlueCell(int dayOfMon, Rect rect, float s, boolean bold, int type) {
			super(dayOfMon, rect, s, bold, type);
			mPaint.setColor(Color.parseColor("#33ccff"));

		}
	}

	private class TodayBlueCell extends Cell {
		public TodayBlueCell(int dayOfMon, Rect rect, float s, boolean bold,
				int type) {
			super(dayOfMon, rect, s, bold, type);
			mPaint.setColor(Color.parseColor("#33ccff"));
			mPaint.setUnderlineText(true);
		}
	}

	private class TodayCell extends Cell {
		public TodayCell(int dayOfMon, Rect rect, float s) {
			super(dayOfMon, rect, s);
			mPaint.setUnderlineText(true);
		}

	}

    public static int getDipValue(int param, Resources res){
    	return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, param, res.getDisplayMetrics());
    }
    	
}
